import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import {
  Repository,
  In,
  // Like,
  Not,
  Between,
} from 'typeorm';
import unzipper from 'unzipper';
import typeorm from 'typeorm';
import isZip from 'is-zip';
// import { Logs } from 'src/logs/entity/logs.entity';
// import { HttpOrder } from './httpOrder.entity';
// import ProductionOrder from '../modules/admin/production/production-order.entity'
// import { BaseMachineService } from '../modules/admin/base/machine/machine.service';
import BaseMachine from '@main/entities/service/admin/base/base-machine.entity';
import BaseMaterial from '@main/entities/service/admin/base/base-material.entity';
import ProductionOrder from '@main/entities/service/admin/production/production-order.entity';
import WipOrderReport from '@main/entities/service/admin/wip/wip-order-report.entity';
// import { UtilService } from '@main/shared/services/util.service';
import { ProductionOrderService } from '@main/service/modules/admin/production/order/order.service';
import { BaseCustomService } from '@main/service/modules/admin/base/custom/custom.service';
// import archiver from 'archiver';
import * as fs from 'fs';
import { app } from 'electron';
import * as path from 'path';
import { join } from 'path';
import * as fse from 'fs-extra';
// import { zip } from 'compressing';
import * as compressing from 'compressing';
import { deleteFolderRecursive } from './utils';
import SysOperationLog from '@main/entities/service/admin/sys/sys-operation-log.entity';
import SysUser from '@main/entities/service/admin/sys/sys-user.entity';
import SysUserRole from '@main/entities/service/admin/sys/sys-user-role.entity';
import SysRole from '@main/entities/service/admin/sys/sys-role.entity';
// import { WipOrderReportService } from '@main/service/modules/admin/wip/orderReport/orderReport.service';
import SysErpField from '@main/entities/service/admin/sys/sys-erp-field.entity';

@Injectable()
export class HttpOrderService {
  constructor(
    @InjectRepository(BaseMachine)
    private machineFindRepository: Repository<BaseMachine>,
    @InjectRepository(BaseMaterial)
    private materialFindRepository: Repository<BaseMaterial>,
    @InjectRepository(ProductionOrder)
    private orderFindRepository: Repository<ProductionOrder>,
    @InjectRepository(WipOrderReport)
    private wipOrderReportFindRepository: Repository<WipOrderReport>,
    // private util: UtilService,
    private orderSer: ProductionOrderService,
    private customSer: BaseCustomService, // private orderReport: WipOrderReportService
    @InjectRepository(SysOperationLog) private operationLogRepository: Repository<SysOperationLog>,
    @InjectRepository(SysUser) private userRepository: Repository<SysUser>,
    @InjectRepository(SysUserRole)
    private userRoleRepository: Repository<SysUserRole>,
    @InjectRepository(SysRole)
    private roleRepository: Repository<SysRole>,
    @InjectRepository(SysErpField)
    private erpFieldRepository: Repository<SysErpField>
  ) {
    this.databaseMap = {
      SysUser: this.userRepository,
      SysUserRole: this.userRoleRepository,
      SysRole: this.roleRepository,
    };
  }

  databaseMap = {};

  async validateOrder(
    dto: any,
    lang,
    mac,
    ip,
    syncHostSqlite
  ): Promise<{ status: string; message: string; data: any }> {
    const fieldList = await this.erpFieldRepository.find();

    let order = dto;

    if (fieldList.length) {
      for (const item of fieldList) {
        const { field, newField } = item;

        if (field && newField && order[newField]) {
          order[field] = order[newField];
        }
      }
    }

    if (order.command == 1000) {
      // 增加订单
      const {
        command,
        machineCode,
        proOrder,
        customerCode,
        customerName,
        customerBoxModel,
        paperTexture,
        corrugatedTypeId,
        materialLength,
        materialWidth,
        materialHeight,
        unit,
        cartonTypeId,
        nail,
        lid,
        orderNum,
        paperboardLength,
        paperboardWidth,
        paperboardNum,
        templateNum,
        orderTypeId,
        materialCode,
        materialName,
        materialPicture,
        customerDeliveryDate,
        erpNo,
        version,
      } = order;

      // 检查必填参数是否为空
      if (
        !command ||
        !machineCode ||
        !proOrder ||
        !customerCode ||
        !customerName ||
        !customerBoxModel ||
        !paperTexture ||
        !corrugatedTypeId ||
        !materialLength ||
        !materialWidth ||
        !materialHeight ||
        !unit ||
        !cartonTypeId ||
        !nail ||
        !lid ||
        !orderNum ||
        !paperboardLength ||
        !paperboardWidth ||
        !paperboardNum ||
        !templateNum ||
        !orderTypeId ||
        !materialCode ||
        !materialName ||
        !materialPicture ||
        !customerDeliveryDate ||
        !erpNo
      ) {
        return { status: 'E', message: 'E11', data: null }; //必填参数为空
      }

      // 校验machineCode是否有设备参数表中的编码
      // const machineFind = await this.baseMachineService.isExistKey(machineCode);
      // console.log('machineFind',machineFind)
      const machineFind = await this.machineFindRepository.findOne({ where: { machineCode } });
      console.log('machineFind', machineFind);
      if (!machineFind) {
        return { status: 'E', message: 'E09', data: null }; //machineCode校验失败
      }

      // 检查未生产的订单表中是否有相同的生产单号
      const orderFind = await this.orderFindRepository.find({
        where: {
          // machineCode,//?看情况
          orderStatusCode: Not(In(['40', '50'])),
          erpNo,
        },
      });
      console.log('orderFind', orderFind);
      console.log('orderFind.length', orderFind.length);
      if (orderFind && orderFind.length > 0) {
        return { status: 'E', message: 'E01', data: null }; //存在相同的生产单号
      }

      //检查是否有该产品,无 新增, 有是否有当前版本号,无 新增.
      // materialFindRepository
      const materialList: any = await this.materialFindRepository.findOne({
        where: { materialCode },
      });
      if (!materialList) {
        // 新增产品
        console.log('新增产品');
        await this.materialFindRepository.insert(order);
      } else if (materialList && version) {
        let materialVer = materialList.map((i) => i.version === version);
        if (!materialVer) {
          // 无当前版本
          console.log('无当前版本');
        } else {
          // 有当前版本 next 继续-》
          console.log('有当前版本 next 继续-》');
        }
      } else {
        // 有产品无版本号
        console.log('有产品无版本号');

        // 检查是否有空版本号的产品，无 新增
        await this.materialFindRepository.findOne({ where: { materialCode } });
      }

      // 判断有无客户，无 新增
      let customS = await this.customSer.isExistCode(customerCode);
      if (!customS) {
        await this.customSer.add(
          {
            customCode: customerCode,
            customName: customerName,
            customer: customerName,
          },
          { nickName: 'erp', userName: 'erp' },
          mac,
          ip,
          syncHostSqlite
        );
      }

      // 创建新订单并保存到数据库中
      await this.orderSer.add(
        {
          ...order,
          ...{
            customer: customerName,
            customerNo: customerCode,
            paperLength: paperboardLength,
            paperWidth: paperboardWidth,
          },
        },
        lang,
        { nickName: 'erp', userName: 'erp' },
        mac,
        ip,
        syncHostSqlite
      );

      // 执行成功，返回执行成功的数据
      return { status: 'S', message: null, data: null };
    } else if (order.command == 1050) {
      // 删除指定的生产单号
      // 检查未生产的订单表中是否有相同的生产单号
      const orderFind = await this.orderFindRepository.find({
        where: {
          orderStatusCode: Not(In(['50'])),
          erpNo: order.erpNo,
        },
      });
      if (orderFind && orderFind.length > 0) {
        let orderFindS = orderFind.filter((item) =>
          ['30', '40', '60'].includes(item.orderStatusCode)
        );
        if (orderFindS && orderFindS.length > 0) {
          return { status: 'E', message: 'E16', data: null }; //指定删除的生产单号=生产中/暂停/完工
        } else {
          // 执行删除
          let idList = orderFind.map((item) => item.id);
          let deletes = await this.orderSer.deleteRecords(idList);
          if (deletes && deletes.affected && deletes.affected > 0) {
            return { status: 'S', message: null, data: null };
          } else {
            return { status: 'E', message: 'E13', data: null };
          }
        }
      } else {
        return { status: 'E', message: 'E13', data: null }; //指定删除的生产单号不存在
      }
    } else if (order.command == 1030) {
      // 调整生产工单顺序
      // 检查未生产的订单表中是否有相同的生产单号
      const orderFind = await this.orderFindRepository.find({
        where: {
          orderStatusCode: Not(In(['50'])),
          erpNo: order.erpNo,
        },
      });
      console.log('orderFind', orderFind);
      if (orderFind && orderFind.length > 0) {
        let orderFindS = orderFind.filter((item) =>
          ['30', '40', '60'].includes(item.orderStatusCode)
        );
        if (orderFindS && orderFindS.length > 0) {
          return { status: 'E', message: 'E15', data: null }; //指定的生产单号=生产中/暂停/完工
        } else {
          // 执行更新
          // let idList = orderFind.map((item) => item.id);
          let proOrder = await this.orderSer.adjustOrder(order.erpNo, { proOrder: order.proOrder });
          if (proOrder && proOrder.affected && proOrder.affected > 0) {
            return { status: 'S', message: null, data: null };
          } else {
            return { status: 'E', message: 'E14', data: null }; //指定的生产单号不存在
          }
        }
      } else {
        return { status: 'E', message: 'E14', data: null }; //指定的生产单号不存在
      }
    } else {
      // 数据错误
      return { status: 'E', message: 'E18', data: null }; //command校验失败
    }
  }

  async findByDateAndProOrder(dto: any): Promise<{ status: string; message: string; data: any }> {
    const fieldList = await this.erpFieldRepository.find();

    let body = dto;

    let keyMapObj = null;

    if (fieldList.length) {
      for (const item of fieldList) {
        const { field, newField } = item;

        if (field && newField && body[newField]) {
          body[field] = body[newField];

          if (!keyMapObj) {
            keyMapObj = {};
          }

          keyMapObj[field] = newField;
        }
      }
    }

    if (!body.date && !body.machineCode && !body.erpNo) {
      return { status: 'E', message: '400', data: null };
    }

    // 检查未生产的订单表中是否有相同的生产单号
    const result = await this.wipOrderReportFindRepository.find({
      where: {
        reportTime: (body.date
          ? Between(
              new Date(`${body.date} 00:00:00`).getTime(),
              new Date(`${body.date} 23:59:59`).getTime()
            )
          : null) as any,
        machineCode: body.machineCode ? body.machineCode : null,
        erpNo: body.erpNo ? body.erpNo : null,
      },
    });

    if (result && result.length > 0) {
      result.forEach((item: any) => {
        item.orderNo = item.orderCode;

        if (keyMapObj) {
          for (const key in item) {
            if (keyMapObj[key]) {
              item[keyMapObj[key]] = item[key];
            }
          }
        }
      });
      return { status: 'S', message: '', data: result };
    }
    return { status: 'E', message: '400', data: null };
  }

  time = null;

  async getSqlite() {
    if (this.time) {
      clearTimeout(this.time);

      this.time = null;
    }

    return await new Promise(async (resolve) => {
      const folderPath = join(`${app.getPath('userData')}`, '/Sqlite');

      const copyPath = join(`${app.getPath('userData')}`, '/CopySqlite');

      await fse.copy(folderPath, copyPath);

      const filePath = join(app.getPath('userData'), '/Zip/sqlite.zip');

      // // console.log(filePath);

      const directoryPath = path.dirname(filePath);

      // console.log(directoryPath);

      if (!fs.existsSync(directoryPath)) {
        fs.mkdirSync(directoryPath, { recursive: true });
      }

      // const outputPath = `${app.getPath('userData')}/Zip/sqlite.zip`;

      // const output = fs.createWriteStream(outputPath);

      // await compressing.zip.compressDir(hostPath, filePath);

      // resolve(filePath);

      // console.log(hostPath)

      const tarStream = new compressing.zip.Stream();

      const files = fs.readdirSync(copyPath);

      files.forEach((file) => {
        const fileFullPath = path.join(copyPath, file);

        tarStream.addEntry(fileFullPath);
      });

      // console.log(outputPath);

      // await tarStream.addEntry(hostPath);

      this.time = setTimeout(() => {
        deleteFolderRecursive(copyPath);
      }, 3000);

      resolve(tarStream);

      // console.log(tarStream);

      // return filePath;

      // console.log(archiver);

      // const archive = archiver('zip', { zlib: { level: 9 } });

      // output.on('close', () => {
      //   console.log(`${archive.pointer()} total bytes`);
      //   console.log('archiver has been finalized and the output file descriptor has closed.');

      //   resolve(data);
      // });

      // archive.pipe(output);

      // archive.directory(hostPath, false);

      // await archive.finalize();

      // console.log(11);

      // data = fs.readFileSync(outputPath);

      // fs.unlinkSync(outputPath); // 删除zip文件
    });
  }

  async getUploadFile() {
    return await new Promise(async (resolve) => {
      const folderPath = join(`${app.getPath('userData')}`, '/UploadFile');

      // const filePath = join(app.getPath('userData'), '/Zip/uploadFile.zip');

      // // console.log(filePath);

      // const directoryPath = path.dirname(filePath);

      // console.log(directoryPath);

      // if (!fs.existsSync(directoryPath)) {
      //   fs.mkdirSync(directoryPath, { recursive: true });
      // }

      const tarStream = new compressing.zip.Stream();

      tarStream.addEntry(folderPath);

      resolve(tarStream);
    });
  }

  setWhereObjFn(logItem) {
    const { whereObj, dataType } = logItem;

    if (dataType === 'typeormObj' && whereObj) {
      const obj = {};

      for (const i in whereObj) {
        const { typeorm: wTypeorm, data } = whereObj[i];

        obj[i] = wTypeorm ? typeorm[wTypeorm](data) : data;
      }

      return obj;
    }

    return whereObj;
  }

  async syncSqlite(list) {
    // console.log(list);

    await Promise.all(
      list.map(async (item) => {
        const obj = await this.operationLogRepository.findOne({ where: { id: item.id } });

        if (!obj || obj.syncHostSqlite === 1) {
          const databaseOperationLogList = item.databaseOperationLogList
            ? JSON.parse(item.databaseOperationLogList)
            : [];

          const { databaseMap } = this;

          let shouldBreak = false;

          await Promise.all(
            databaseOperationLogList.map(async (logItem) => {
              try {
                if (shouldBreak) return; // 如果需要跳出循环，则直接返回

                const { data, dataType, database, type, checkOnlyKeyList, whereObj } = logItem;

                let checkOnlyKeyListObj = null;

                let where = whereObj ? this.setWhereObjFn(logItem) : null;

                if (dataType === 'obj' && checkOnlyKeyList && checkOnlyKeyList.length) {
                  where = checkOnlyKeyList.reduce((acc, prop) => {
                    acc[prop] = data[prop];
                    return acc;
                  }, {});

                  checkOnlyKeyListObj = await databaseMap[database].findOne({ where });
                }

                if (checkOnlyKeyListObj) {
                  const { updateTime } = checkOnlyKeyListObj;
                  const cUpdateTime = new Date(updateTime).getTime();
                  const dUpdateTime = new Date(data.updateTime).getTime();

                  if (dUpdateTime > cUpdateTime) {
                    await databaseMap[database].update(where, data);
                  } else {
                    shouldBreak = true; // 设置标志位，表示应该跳出循环
                  }
                } else {
                  switch (type) {
                    case 'add':
                      await databaseMap[database].insert(data);
                      break;
                    case 'update':
                      await databaseMap[database].update(where, data);
                      break;
                    case 'delete':
                      await databaseMap[database].delete(where);
                      break;
                    default:
                      break;
                  }
                }
              } catch (e) {
                console.log(logItem);
                console.log(e);
              }
            })
          );

          try {
            if (!obj) {
              await this.operationLogRepository.insert({
                ...item,
                syncHostSqlite: 0,
              });
            } else {
              await this.operationLogRepository.update({ id: obj.id }, { syncHostSqlite: 0 });
            }
          } catch (error) {
            // 错误处理
            console.error('An error occurred:', error);
          }
        }
      })
    );
  }

  async unzipAndCompare(zipData, extractPath) {
    const zipFilePath = `${app.getPath('userData')}/Zip/uploadFile.zip`;

    await fs.promises.writeFile(`${app.getPath('userData')}/Zip/uploadFile.zip`, zipData);

    await fs
      .createReadStream(zipFilePath)
      .pipe(unzipper.Extract({ path: extractPath }))
      .promise();

    const files = await unzipper.Open.file(zipFilePath);

    for (const file of files.files) {
      const extractedFilePath = extractPath + '/' + file.path;
      if (fs.existsSync(extractedFilePath)) {
        const localStats = fs.statSync(extractedFilePath);
        if (localStats.mtime < file.lastModified) {
          // ZIP 文件中的文件修改时间比本地文件更新，覆盖本地文件
          console.log(`Updating file: ${extractedFilePath}`);
          await file.extract({ path: extractPath, overwrite: true });
        } else {
          console.log(`Skipping file: ${extractedFilePath}`);
        }
      } else {
        // 本地不存在该文件，直接新增
        console.log(`Adding new file: ${extractedFilePath}`);
        await file.extract({ path: extractPath, overwrite: false });
      }
    }

    console.log('Extraction and comparison complete.');
  }

  async syncUploadFile(buffer) {
    const data = Buffer.from(buffer, 'binary');

    if (isZip(data)) {
      await this.unzipAndCompare(data, `${app.getPath('userData')}`);

      console.log('同步本地上传文件');
    } else {
      console.log('上传文件类型有误');
    }
  }
}
